package com.robinmouren.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.robinmouren.constant.MessageConstant;
import com.robinmouren.constant.NumberConstant;
import com.robinmouren.constant.OrderConstant;
import com.robinmouren.constant.StatusConstant;
import com.robinmouren.dto.ClientOrderDto;
import com.robinmouren.dto.QuotationDto;
import com.robinmouren.entity.*;
import com.robinmouren.exception.ErrorOrderInfoException;
import com.robinmouren.exception.NullInfoException;
import com.robinmouren.exception.NullOrderInfoException;
import com.robinmouren.mapper.OrderMapper;
import com.robinmouren.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.robinmouren.utils.DateUtils;
import com.robinmouren.utils.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author Robinmouren
 * @since 2024-05-12
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements IOrderService {

    @Autowired
    private QuoteServiceImpl quoteService;
    @Autowired
    private OrderDetailServiceImpl orderDetailService;
    @Autowired
    private RedisTemplate<String, List<OrderStatus>> redisTemplate;
    @Autowired
    private SplitGoodsServiceImpl goodsService;
    @Autowired
    private SplitRouteServiceImpl routeService;
    @Autowired
    private ThreadPoolTaskExecutor executor;


    /**
     * 客户端创建询价单
     *
     * @param quotationDto
     */
    @Override
    public void quotationCreate(QuotationDto quotationDto) {

        // 获取dto中的信息
        TransportAddress address = quotationDto.getAddress();
        LocalDateTime loading = quotationDto.getPlanedTime().getLoading();
        LocalDateTime unload = quotationDto.getPlanedTime().getUnload();
        // 货物物品信息
        List<LoadInformation> loadInformation = quotationDto.getLoadInfo().getLoadInformation();
        // 货物数量信息
        Total total = quotationDto.getLoadInfo().getTotal();
        String remarks = quotationDto.getRemarks();

        // 对信息进行处理
        // 判断时间格式是否符合规范
        if (!DateUtils.ifStartAndEndSpecification(loading, unload)) {
            throw new ErrorOrderInfoException(MessageConstant.DATETIME_NOT_SPECIFICATION);
        }


        // 获取随机订单号
        String number = StringUtils.generateOrderNumber(OrderConstant.ORDER);
        // 将地址信息连接在一起
        String originPlace = StringUtils.makeStringTogether(address.getOrigin(), address.getOriginDetail());
        String destination = StringUtils.makeStringTogether(address.getDestination(), address.getDestinationDetail());
        OrderInfo build = OrderInfo.builder()
                .userId(Long.parseLong(quotationDto.getId()))
                .orderNumber(number)
                .originPlace(originPlace)
                .destination(destination)
                .status(StatusConstant.CREATE_QUOTATION)
                .loading(loading)
                .unload(unload)
                .weights(total.getWeight())
                .remarks(remarks)
                .build();
        // 在订单表中添加信息
        this.save(build);

        // 获取刚添加的订单id

        OrderInfo one = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNumber, number));

        loadInformation.forEach(item -> {
            // 在订单细明表中添加信息
            OrderDetail orderDetail = OrderDetail.builder()
                    .orderId(one.getId())
                    .name(item.getName())
                    .quantity(item.getQuantity())
                    .specification(item.getSpecification())
                    .volumes(item.getVolumes())
                    .weights(item.getWeights())
                    .wraps(item.getWraps())
                    .build();
            orderDetailService.save(orderDetail);
        });

        // 将订单状态信息存入map集合
        // 将订单的状态存到redis中
        // TODO 设置过期时间
        List<OrderStatus> list = OrderStatus.listQuotation();
        redisTemplate.opsForValue().set(one.getOrderNumber(), list);


    }


    /**
     * 获取订单信息，根据订单号
     *
     * @param orderNumber
     * @return
     */
    @Override
    public QuotationDto getByOrderNumber(String orderNumber) {
        OrderInfo one = this.getOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNumber, orderNumber));
        if (one == null) {
            throw new NullOrderInfoException(MessageConstant.ORDER_IS_NULL);
        }

        // 获取货物详细信息
        List<OrderDetail> list = orderDetailService.list(
                new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, one.getId()));
        // 处理信息
        List<LoadInformation> collect = list.stream().map(item -> {
            LoadInformation loadInformation = new LoadInformation();
            BeanUtils.copyProperties(item, loadInformation);
            return loadInformation;
        }).collect(Collectors.toList());
        Total total = new Total(NumberConstant.ZERO, NumberConstant.ZERO, NumberConstant.ZERO);
        // 处理运输地址信息
        TransportAddress address = StringUtils.removeSignToObject(one.getOriginPlace(), one.getDestination());

        return QuotationDto.builder()
                .id(one.getUserId().toString())
                .address(address)
                .planedTime(new PlanedTime(one.getLoading(), one.getUnload()))
                .loadInfo(new LoadInfo(collect, total))
                .opinion(one.getOpinion())
                .remarks(one.getRemarks())
                .build();

    }

    /**
     * 订单修改状态
     *
     * @return
     */
    @Override
    public void quotationStatusUpdate(String orderNumber, Integer code) {

        OrderInfo info = this.getOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNumber, orderNumber));
        if (info == null) {
            throw new NullOrderInfoException(MessageConstant.ORDER_IS_NULL);
        }
        info.setStatus(code);
        this.update(info, new LambdaUpdateWrapper<OrderInfo>()
                .set(OrderInfo::getStatus, code)
                .eq(OrderInfo::getOrderNumber, orderNumber));

        if (code.equals(NumberConstant.MINUS_ONE)) {
            redisTemplate.opsForValue().set(orderNumber, new ArrayList<>());
            return;
        }

        // 将缓存中订单的状态信息修改
        List<OrderStatus> list = redisTemplate.opsForValue().get(orderNumber);
        // 订单信息为空
        if (list == null) {
            throw new NullOrderInfoException(MessageConstant.ORDER_IS_NULL);
        }
        OrderStatus.reviseList(list, code, LocalDateTime.now());
        // 重新将值存入
        redisTemplate.opsForValue().set(orderNumber, list);
    }


    /**
     * 询价单添加审核意见
     *
     * @param orderNumber
     * @param opinion
     */
    @Override
    public void quotationAuditOpinion(String orderNumber, String opinion) {
        OrderInfo info = this.getOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNumber, orderNumber));
        if (info == null) {
            throw new NullOrderInfoException(MessageConstant.ORDER_IS_NULL);
        }
        this.update(info,
                new LambdaUpdateWrapper<OrderInfo>()
                        .set(OrderInfo::getOpinion, opinion)
                        .eq(OrderInfo::getOrderNumber, orderNumber)
        );
    }


    /**
     * 客户下单
     *
     * @param dto
     */
    @Override
    public void clientPlaceOrder(ClientOrderDto dto) {

        String orderNumber = dto.getOrderNumber();
        Principal principal = dto.getPrincipal();
        Receiving receiving = dto.getReceiving();

        // 获取订单信息，以获取id
        OrderInfo orderinfo = this.getOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNumber, orderNumber));
        if (orderinfo == null) {
            throw new NullOrderInfoException(MessageConstant.ORDER_IS_NULL);
        }
        // 修改订单状态
        OrderInfo orderInfo = OrderInfo.builder()
                .weights(orderinfo.getWeights())
                .principal(principal.getPrincipal())
                .client(principal.getName())
                .clientPhone(principal.getPhone())
                .principalDetailedAddress(principal.getAddress())
                .consignee(receiving.getReceiving())
                .receiving(receiving.getName())
                .receivingPhone(receiving.getPhone())
                .consigneeDetailedAddress(receiving.getAddress())
                .status(StatusConstant.CLIENT_ORDER).build();
        this.update(orderInfo,
                new LambdaUpdateWrapper<OrderInfo>()
                        .eq(OrderInfo::getId, orderinfo.getId()));

        // 修改订单map状态，修改成订单状态map
        List<OrderStatus> list = OrderStatus.listOrder();
        redisTemplate.opsForValue().set(orderNumber, list);

    }


    /**
     * 根据订单号取消所有拆分信息
     *
     * @param orderNumber
     */
    @Override
    public void cancelSplit(String orderNumber) {
        // 获取订单id
        OrderInfo orderinfo = this.getOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNumber, orderNumber));
        Long id = orderinfo.getId();

        // 获取拆分的货物信息，若存在则删除
        List<SplitGoods> ifExistList1 = goodsService.list(new LambdaQueryWrapper<SplitGoods>()
                .eq(SplitGoods::getOrderId, id));
        if(ifExistList1.size() > 0){
            goodsService.removeBatchByIds(ifExistList1);
            // 查询货物细明表中是否有信息，若有则删除
            List<OrderDetail> list = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>()
                    .eq(OrderDetail::getOrderId, id)
                    .and(wrapper -> {
                        wrapper.ne(OrderDetail::getTrackingNumber,null);
                    }));
            if(list.size() > 0){
                orderDetailService.removeBatchByIds(list);
            }
        }

        // 获取拆分的路线信息，若存在则删除
        List<SplitRoute> ifExistList2 = routeService.list(new LambdaQueryWrapper<SplitRoute>()
                .eq(SplitRoute::getOrderId, id));
        if(ifExistList2.size() > 0){
            routeService.removeBatchByIds(ifExistList2);
        }


        // 修改订单状态
        orderinfo.setStatus(StatusConstant.CLIENT_ORDER);
        this.updateById(orderinfo);

        // 修改缓存中的状态
        executor.execute(() -> {
            // 获取创建时的时间
            List<OrderStatus> orderStatusList = redisTemplate.opsForValue().get(orderNumber);
            if(orderStatusList == null ||orderStatusList.size() < 1){
                throw new NullInfoException(MessageConstant.SPLIT_ROUTE_IS_NULL);
            }
            LocalDateTime time = orderStatusList.get(0).getTime();
            // 重新赋值
            List<OrderStatus> orderStatuses = OrderStatus.listOrder();
            orderStatuses.get(0).setTime(time);
            redisTemplate.opsForValue().set(orderNumber, orderStatuses);
        });
    }
}
